package demo;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

/**
 * PowerMockit示例
 * 注意点：
 * @ RunWith 该注解标识通过PowerMockit执行单元测试
 * @ PrepareForTest 对静态方法所在的Class进行生命，多个使用","进行分割
 * PowerMockito.mockStatic(class) 对静态方法所在的class生成模拟对象，屏蔽方法调用
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticClassDemo.class, PowerMockDemoImpl.class, PowerMockDemoImpl.InnerStaticClass.class})
public class PowerMockDemoImplTest {

    @InjectMocks
    PowerMockDemoImpl powerMockDemo;

    @Before
    public void before(){
        PowerMockito.mockStatic(StaticClassDemo.class);
        PowerMockito.mockStatic(PowerMockDemoImpl.class);
        PowerMockito.mockStatic(PowerMockDemoImpl.InnerStaticClass.class);
    }

    /**
     * 待测试的方法内通过成员属性调用静态方法
     */
    @Test
    public void useStaticMethod_withFiled_withNoReturnAndArgs_test(){
        // 由于是静态方法，虽然是通过成员属性调用，但mockStatic的class生效
        powerMockDemo.useStaticMethod_withFiled_withNoReturnAndArgs();
    }

    /**
     * 调用的静态方法是public类型，并且没有入参与返回值，这样只是需要通过mock静态类即可：
     * PowerMockito.mockStatic(StaticClassDemo.class)
     */
    @Test
    public void useStaticMethod_withNoReturnAndArgs_test(){
        powerMockDemo.useStaticMethod_withNoReturnAndArgs();
    }

    /**
     * 调用的静态方法是public类型，并且没有入参与返回值，这样只是需要通过mock静态类即可：
     * PowerMockito.mockStatic(PowerMockDemoImpl.class);
     */
    @Test
    public void useStaticMethod_noReturnAndArgsWithPrivate_test(){
        powerMockDemo.useStaticMethod_noReturnAndArgsWithPrivate();
    }

    @Test
    public void useStaticMethod_withFiled_noArgsWithBasicIntReturn_test(){
        //通过when()...thenAnswer()进行设置，使用lambda进行简化
        PowerMockito.when(StaticClassDemo.noArgsWithBasicIntReturn())
                .thenAnswer(inv->1);
        powerMockDemo.useStaticMethod_withFiled_noArgsWithBasicIntReturn();
    }

    @Test
    public void useStaticMethod_noArgsWithBasicIntReturn_test(){
        //通过when()...thenAnswer()进行设置，使用lambda进行简化
        PowerMockito.when(StaticClassDemo.noArgsWithBasicIntReturn())
                .thenAnswer(inv->1);
//        // lambda简化前方式
//        PowerMockito.when(StaticClassDemo.noArgsWithBasicIntReturn()).thenAnswer(new Answer<Integer>() {
//            @Override
//            public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
//                return 1;
//            }
//        });
        // 在不关注返回值的场景下，可忽略when()...then()
        powerMockDemo.useStaticMethod_noArgsWithBasicIntReturn();
    }

    @Test
    public void useStaticMethod_noArgsWithBasicIntReturnPrivate_test() throws Exception {
        // 通过when()...thenAnswer()进行设置，使用lambda进行简化
        PowerMockito.when(PowerMockDemoImpl.class, "noArgsWithBasicIntReturnPrivate").thenAnswer(inv -> 1);
//        // lambda简化前方式
//        PowerMockito.when(PowerMockDemoImpl.class, "noArgsWithBasicIntReturnPrivate").thenAnswer(new Answer<Integer>() {
//            @Override
//            public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
//                return 1;
//            }
//        });
        // 在不关注返回值的场景下，可忽略when()...then()
        powerMockDemo.useStaticMethod_noArgsWithBasicIntReturnPrivate();
    }

    @Test
    public void useStaticMethod_withFiled_noReturnWithIntArg_test(){
        int arg = 1;
        powerMockDemo.useStaticMethod_withFiled_noReturnWithIntArg(arg);
    }

    @Test
    public void useStaticMethod_noReturnWithIntArg_test(){
        int arg = 1;
        // 由于已经对class进行过mock，没涉及到返回值场景，所以可以直接使用
        powerMockDemo.useStaticMethod_noReturnWithIntArg(arg);
    }

    @Test
    public void useStaticMethod_noReturnWithIntArgPrivate_test(){
        int arg = 1;
        // 由于已经对class进行过mock，没涉及到返回值场景，所以可以直接使用
        powerMockDemo.useStaticMethod_noReturnWithIntArgPrivate(arg);
    }

    @Test
    public void useStaticMethod_withFiled_withIntReturnAndArg_test(){
        int arg = 1;
        // 通过when()...thenAnswer()进行设置，使用lambda进行简化
        PowerMockito.when(StaticClassDemo.withIntReturnAndArg(arg)).thenAnswer(inv -> 2);
        powerMockDemo.useStaticMethod_withFiled_withIntReturnAndArg(arg);
    }

    @Test
    public void useStaticMethod_withIntReturnAndArg_test(){
        int arg = 1;
        // 通过when()...thenAnswer()进行设置，使用lambda进行简化
        PowerMockito.when(StaticClassDemo.withIntReturnAndArg(arg)).thenAnswer(inv -> 2);
        powerMockDemo.useStaticMethod_withIntReturnAndArg(arg);
    }

    @Test
    public void useStaticMethod_withIntReturnAndArgPrivate_test() throws Exception {
        Integer arg = 1;
        // 通过when()...thenAnswer()进行设置，使用lambda进行简化
        PowerMockito
                .when(PowerMockDemoImpl.class, "withIntReturnAndArgPrivate", arg)
                .thenAnswer(inv -> 2);
        powerMockDemo.useStaticMethod_withIntReturnAndArgPrivate(arg);
    }

    @Test
    public void useStaticMethod_innerMethod_noReturnAndArgs_test(){
        powerMockDemo.useStaticMethod_innerMethod_noReturnAndArgs();
    }

    @Test
    public void useStaticMethod_innerMethod_noReturnAndIntArg_test(){
        int arg = 1;
        powerMockDemo.useStaticMethod_innerMethod_noReturnAndIntArg(arg);
    }

    @Test
    public void useStaticMethod_innerMethod_intReturnAndNoArg_test(){
        PowerMockito.when(PowerMockDemoImpl.InnerStaticClass.innerMethod_intReturnAndNoArg())
                .thenAnswer(inv -> 2);
        powerMockDemo.useStaticMethod_innerMethod_intReturnAndNoArg();
    }

    @Test
    public void useStaticMethod_innerMethod_intReturnAndIntArg_test(){
        int arg = 1;
        PowerMockito.when(PowerMockDemoImpl.InnerStaticClass.innerMethod_intReturnAndIntArg(arg))
                .thenAnswer(inv -> 2);
        powerMockDemo.useStaticMethod_innerMethod_intReturnAndIntArg(arg);
    }

}
